package com.qihoo.finance.lcs.enhance.threadpool.impl;

import com.google.common.base.Stopwatch;
import com.qihoo.finance.lcs.enhance.threadpool.ThreadPoolNameService;
import com.qihoo.finance.msf.core.test.SpringTestCase;
import com.qihoo.finance.msf.threadpool.ThreadPool;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPoolServiceImplTestV2 extends SpringTestCase {
    private static final Logger LOGGER = LogManager.getLogger();

    @Resource
    private ThreadPool threadPool;

    private com.qihoo.finance.lcs.enhance.threadpool.ThreadPoolService threadPoolService;

    @Before
    public void setup(){
        threadPoolService = new ThreadPoolServiceImpl(threadPool);
    }

    enum ThreadPoolNameEnum implements ThreadPoolNameService {

        TEST("TEST"),
        TEST_NOT_EXISTS("TEST_NOT_EXISTS")
        ;

        private String threadPoolName;

        ThreadPoolNameEnum(String threadPoolName) {
            this.threadPoolName = threadPoolName;
        }

        @Override
        public String getThreadPoolName() {
            return threadPoolName;
        }
    }

    @Test
    public void test_run_single() throws InterruptedException {
        int times = 1;
        int mul = 100;
        CountDownLatch countDownLatch = new CountDownLatch(mul);
        AtomicInteger count = new AtomicInteger(0);
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int j = 0; j < mul; j++) {
            //threadPoolService.submit(() -> {
            for (int i = 0; i < times; i++) {
                //LOGGER.info("准备自增操作");
                count.incrementAndGet();
            }
            countDownLatch.countDown();
            //}, workId.incrementAndGet(),"TEST");
        }

        countDownLatch.await();
        stopwatch.stop();
        LOGGER.info("执行完毕,{}", stopwatch);
        Assert.assertEquals(mul * times, count.get());
    }

    @Test
    public void test_run() throws InterruptedException {
        AtomicInteger workId = new AtomicInteger(0);
        int times = 1;
        int mul = 100;
        CountDownLatch countDownLatch = new CountDownLatch(mul);
        AtomicInteger count = new AtomicInteger(0);
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int j = 0; j < mul; j++) {
            threadPoolService.submit(() -> {
                for (int i = 0; i < times; i++) {
                    LOGGER.info("准备自增操作");
                    count.incrementAndGet();
                }
                countDownLatch.countDown();
            }, workId.incrementAndGet(),ThreadPoolNameEnum.TEST);
        }

        countDownLatch.await();
        stopwatch.stop();
        LOGGER.info("执行完毕,{}", stopwatch);
        Assert.assertEquals(mul * times, count.get());
    }

    @Test
    public void test_run_with_null_work_seq_no() throws InterruptedException {
        int times = 1;
        int mul = 100;
        CountDownLatch countDownLatch = new CountDownLatch(mul);
        AtomicInteger count = new AtomicInteger(0);
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int j = 0; j < mul; j++) {
            threadPoolService.submit(() -> {
                for (int i = 0; i < times; i++) {
                    LOGGER.info("准备自增操作");
                    count.incrementAndGet();
                }
                countDownLatch.countDown();
            }, null,ThreadPoolNameEnum.TEST);
        }

        countDownLatch.await();
        stopwatch.stop();
        LOGGER.info("执行完毕,{}", stopwatch);
        Assert.assertEquals(mul * times, count.get());
    }

    @Test
    public void test_call_with_null_work_seq_no() throws InterruptedException {
        int times = 1;
        int mul = 100;
        List<Future<Integer>> futures = new ArrayList<>();
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int j = 0; j < mul; j++) {
            Future<Integer> future = threadPoolService.call(() -> {
                for (int i = 0; i < times; i++) {
                    //LOGGER.info("准备自增操作");
                }
                return times;
            }, null, ThreadPoolNameEnum.TEST);
            futures.add(future);
        }

        int count = 0;
        for(Future<Integer> future: futures){
            try {
                int t = future.get();
                //LOGGER.info("单个任务执行完毕：{}", t);
                count += t;
            } catch (ExecutionException e) {
                LOGGER.error(e);
            }
        }
        stopwatch.stop();
        LOGGER.info("执行完毕,{}", stopwatch);
        Assert.assertEquals(mul * times, count);
    }

    @Test
    public void test_call_with_incr_work_seq_no() throws InterruptedException {
        int times = 1;
        int mul = 100;
        AtomicInteger seq = new AtomicInteger(0);
        List<Future<Integer>> futures = new ArrayList<>();
        Stopwatch stopwatch = Stopwatch.createStarted();
        for (int j = 0; j < mul; j++) {
            Future<Integer> future = threadPoolService.call(() -> {
                for (int i = 0; i < times; i++) {
                    LOGGER.info("准备自增操作");
                }
                return times;
            }, seq.incrementAndGet(), ThreadPoolNameEnum.TEST);
            futures.add(future);
        }

        int count = 0;
        for(Future<Integer> future: futures){
            try {
                int t = future.get();
                LOGGER.info("单个任务执行完毕：{}", t);
                count += t;
            } catch (ExecutionException e) {
                LOGGER.error(e);
            }
        }
        stopwatch.stop();
        LOGGER.info("执行完毕,{}", stopwatch);
        Assert.assertEquals(mul * times, count);
    }


    @Test
    public void test_exists(){
        boolean exist1 = threadPoolService.isExists(ThreadPoolNameEnum.TEST);
        Assert.assertTrue(exist1);

        boolean exist2 = threadPoolService.isExists(ThreadPoolNameEnum.TEST_NOT_EXISTS);
        Assert.assertFalse(exist2);
    }

}
